package com.boarsoft.boar.code.bean.action;

import java.util.ArrayList;
import java.util.List;

import com.boarsoft.common.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.code.bean.biz.BeanInfoBiz;
import com.boarsoft.boar.code.bean.biz.BeanMappingBiz;
import com.boarsoft.boar.code.bean.biz.BeanPropBiz;
import com.boarsoft.boar.code.entity.BeanInfo;
import com.boarsoft.boar.code.entity.BeanMapping;
import com.boarsoft.boar.code.entity.BeanProp;
import com.boarsoft.common.dao.PagedResult;

@RestController
@RequestMapping(value = "/bean/mapping")
public class BeanMappingAction {
	private static final Logger log = LoggerFactory.getLogger(BeanMappingAction.class);

	private static final int STATUS_VALID = 1;

	private static final String SCRCU_FLOW_DATA = "com.scrcu.core.common.domain.model.ScrcuFlowData";

	private static final String REGEX = "\\.";

	private static final String POINT = ".";
	@Autowired
	private BeanInfoBiz beanInfoBiz;
	@Autowired
	private BeanMappingBiz beanMappingBiz;

	@Autowired
	private BeanPropBiz beanPropBiz;

	/**
	 * 添加来源
	 * 
	 * @param fromType
	 *            来源类型
	 * @param fromObj
	 *            来源对象
	 * @param toType
	 *            目标类型
	 * @param toObj
	 *            目标对象
	 * @param autoMap
	 *            是否自动映射
	 * @param codeId
	 *            对应WrapHandlerInfo或者ProcessHandlerInfo的ID
	 * @return List<BeanMapping>
	 */
	@RequestMapping(value = "/add.do")
	// @Authorized(code = "com.list")
	public ReplyInfo<Object> add(@RequestParam String fromType, @RequestParam String fromObj, @RequestParam String toType,
			@RequestParam String toObj, @RequestParam boolean autoMap, @RequestParam String codeId, @RequestParam String key) {
		List<BeanMapping> beanMappings = new ArrayList<>();
		// 获取目标对象的指定Object的属性列表
		List<BeanProp> toBeanProps = this.getFields(toType, toObj);
		if(SCRCU_FLOW_DATA.equals(fromType)){
			if (CollectionUtils.isEmpty(toBeanProps)) {
				return new ReplyInfo<>(false, "查询目标属性信息为空");
			}
			beanMappings = getSpecialAutoMappingFieldInfo(toBeanProps,fromObj,toObj);
			this.saveDetail(beanMappings, codeId, fromType, toType, key);
			log.info("保存数据成功");
			//return new ReplyInfo<Object>(true, beanMappings);
			return ReplyInfo.SUCCESS;
		}
		// 根据字段名自动映射
		if (autoMap) {
			// 获取来源对象指定object的属性列表
			List<BeanProp> fromBeanProps = this.getFields(fromType, fromObj);

			if (CollectionUtils.isEmpty(fromBeanProps)) {
				return new ReplyInfo<>(false, "查询来源属性信息为空");
			}
			beanMappings = this.getAutoMappingFieldInfo(fromBeanProps, toBeanProps, fromObj, toObj);
		} else {
			String localFromType = this.getType(fromType, fromObj);
			String localToType = this.getType(toType, toObj);
			BeanMapping beanMapping = new BeanMapping();
			beanMapping.setFromType(localFromType);
			beanMapping.setFromObj(fromObj);
			beanMapping.setFromPropType("");
			beanMapping.setFromProp("");
			beanMapping.setToType(localToType);
			beanMapping.setToObj(toObj);
			beanMapping.setToPropType("");
			beanMapping.setToProp("");
			beanMapping.setStatus(STATUS_VALID);
			beanMapping.setCodeId(codeId);
			beanMapping.setKey(key);
			try {
				beanMappingBiz.save(beanMapping);
			} catch (DataIntegrityViolationException e) {
				log.error("保存数据失败，违反唯一约束");
				this.saveDupInfo(beanMapping);
			}
			//return new ReplyInfo<Object>(true, beanMapping);
			return ReplyInfo.SUCCESS;
		}
		this.saveDetail(beanMappings, codeId, fromType, toType, key);
		log.info("保存数据成功");
		//return new ReplyInfo<Object>(true, beanMappings);
		return ReplyInfo.SUCCESS;

	}

	/**
	 * 保存数据列表
	 * 
	 * @param beanMappings
	 *            beanMapping列表
	 * @param codeId
	 *            对应WrapHandlerInfo或者ProcessHandlerInfo的ID
	 * @param fromType
	 *            来源类型
	 * @param toType
	 *            目标类型
	 */
	private void saveDetail(List<BeanMapping> beanMappings, String codeId, String fromType, String toType, String key) {
		beanMappings.forEach(list -> {
			BeanMapping beanMapping = new BeanMapping();
			beanMapping.setFromObj(list.getFromObj());
			beanMapping.setFromProp(list.getFromProp());
			beanMapping.setFromPropType(list.getFromPropType());
			beanMapping.setToObj(list.getToObj());
			beanMapping.setToProp(list.getToProp());
			beanMapping.setToPropType(list.getToPropType());
			beanMapping.setStatus(STATUS_VALID);
			beanMapping.setCodeId(codeId);
			beanMapping.setFromType(fromType);
			beanMapping.setToType(toType);
			beanMapping.setKey(key);
			list.setStatus(STATUS_VALID);
			list.setCodeId(codeId);
			list.setFromType(fromType);
			list.setToType(toType);
			String id = null;
			try {
				id = beanMappingBiz.save(beanMapping);
			} catch (DataIntegrityViolationException e) {
				log.error("保存数据失败，违反唯一约束");
				id = this.saveDupInfo(beanMapping);
			}
			list.setId(id);
		});
	}

	private String saveDupInfo(BeanMapping beanMapping) {
		beanMappingBiz.delete(beanMappingBiz.getBeanMappingId(beanMapping));
		return beanMappingBiz.save(beanMapping);
	}
	/**
	 * 根据字段名自动映射
	 *
	 * @param toBeanProps
	 *            来源属性信息对象
	 * @return 自动映射后的beanMapping信息
	 */
	private List<BeanMapping> getSpecialAutoMappingFieldInfo(List<BeanProp> toBeanProps, String fromObj,
													  String toObj) {
		List<BeanMapping> list = new ArrayList<>();
		for (BeanProp toBeanProp : toBeanProps) {
			BeanMapping beanMappingTemp = new BeanMapping();
			beanMappingTemp.setToObj(toObj);
			beanMappingTemp.setToProp(toBeanProp.getName());
			beanMappingTemp.setToPropType(toBeanProp.getType());
			beanMappingTemp.setFromObj(fromObj);
			beanMappingTemp.setFromProp(toBeanProp.getName());
			beanMappingTemp.setFromPropType(toBeanProp.getType());
			list.add(beanMappingTemp);
		}
		return list;
	}

	/**
	 * 根据字段名自动映射
	 * 
	 * @param fromBeanProps
	 *            来源属性信息对象
	 * @param toBeanProps
	 *            目标属性信息对象
	 * @return 自动映射后的beanMapping信息
	 */
	private List<BeanMapping> getAutoMappingFieldInfo(List<BeanProp> fromBeanProps, List<BeanProp> toBeanProps, String fromObj,
			String toObj) {
		List<BeanMapping> list = new ArrayList<>();
		for (BeanProp toBeanProp : toBeanProps) {
			BeanMapping beanMappingTemp = new BeanMapping();
			beanMappingTemp.setToObj(toObj);
			beanMappingTemp.setToProp(toBeanProp.getName());
			beanMappingTemp.setToPropType(toBeanProp.getType());
			for (BeanProp fromBeanProp : fromBeanProps) {
				if (toBeanProp.getName().equals(fromBeanProp.getName())) {
					beanMappingTemp.setFromObj(fromObj);
					beanMappingTemp.setFromProp(fromBeanProp.getName());
					beanMappingTemp.setFromPropType(fromBeanProp.getType());
					break;
				}
			}
			list.add(beanMappingTemp);
		}
		return list;
	}

	/**
	 * 获取属性列表
	 * 
	 * @param type
	 *            类型
	 * @param obj
	 *            对象
	 * @return bean信息列表
	 */
	private List<BeanProp> getFields(String type, String obj) {
		String typeName = this.getType(type, obj);
		List<BeanInfo> beanInfos = beanInfoBiz.findBeanInfoByType(typeName);
		if (CollectionUtils.isEmpty(beanInfos)) {
			return null;
		}
		return beanPropBiz.findBeanPropByBeanId(beanInfos.get(0).getId(), null);
	}

	/**
	 * 获取最终bean全路径
	 * 
	 * @param type
	 *            类型
	 * @param obj
	 *            对象
	 * @return 实际类型
	 */
	private String getType(String type, String obj) {
		if (obj.contains(POINT)) {
			String[] objList = obj.split(REGEX);
			// 先查询列表
			List<BeanInfo> toBeanInfos = beanInfoBiz.findBeanInfoByType(type);
			for (BeanInfo beanInfo : toBeanInfos) {
				if (objList[1].equals(beanInfo.getName())) {
					String fromobjTmp = obj.substring(obj.indexOf(POINT));
					return getType(beanInfo.getType(), fromobjTmp);
				}
			}

		}
		return type;
	}

	@RequestMapping(value = "/save.do")
	// @Authorized(code = "com.list")
	public ReplyInfo<Object> save(BeanMapping beanMapping) {
		try {
			if(Util.strIsEmpty(beanMapping.getId())){
				beanMappingBiz.save(beanMapping);
			}else {
				beanMappingBiz.update(beanMapping);
			}
		} catch (DataIntegrityViolationException e) {
			beanMappingBiz.update(beanMapping);
		}
		return ReplyInfo.SUCCESS;
	}

	@RequestMapping(value = "/toggle.do")
	// @Authorized(code = "com.list")
	public ReplyInfo<Object> toggle(@RequestParam String id, @RequestParam Boolean enable) {
		beanMappingBiz.toggle(id, enable);
		return ReplyInfo.SUCCESS;
	}

	@RequestMapping(value = "/delete.do")
	// @Authorized(code = "com.list")
	public ReplyInfo<Object> delete(@RequestParam String id) {
		beanMappingBiz.delete(id);
		return ReplyInfo.SUCCESS;
	}

	@RequestMapping(value = "/list.do")
	// @Authorized(code = "com.list")
	public ReplyInfo<Object> list(@RequestParam String codeId, @RequestParam String key, int pageNo, int pageSize) {
		List<BeanMapping> lt = beanMappingBiz.list(codeId, key);
		return new ReplyInfo<Object>(true, //
				new PagedResult<BeanMapping>(lt.size(), lt, pageNo, pageSize));
	}
}
